package com.gitee.zycra.future.job.manager;

import com.gitee.zycra.future.job.common.bo.JobCalculateBO;
import com.gitee.zycra.future.job.common.enums.JobCycleEnum;
import com.gitee.zycra.future.job.common.model.JobSchedule;
import com.gitee.zycra.future.job.common.util.DateUtil;
import com.gitee.zycra.future.job.common.util.IdGenerator;
import com.gitee.zycra.future.job.common.util.UserInfoUtil;
import com.gitee.zycra.future.job.common.vo.JobScheduleNameVO;
import com.gitee.zycra.future.job.dao.JobScheduleDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.ChronoField;
import java.util.List;

/**
 * @author zycra
 */
@Component
public class JobScheduleManager {

    @Autowired
    private JobScheduleDao jobScheduleDao;

    @Autowired
    private IdGenerator idGenerator;

    /**
     * 插入
     *
     * @param jobSchedule 执行信息对象
     * @return 插入条数
     */
    public int insertJobSchedule(JobSchedule jobSchedule) {
        jobSchedule.setId(idGenerator.nextId()).setOperatorId(UserInfoUtil.getUserId()).setOperatorName(UserInfoUtil.getUsername());
        return jobScheduleDao.insertJobSchedule(jobSchedule);
    }

    /**
     * 删除
     *
     * @param id 要删除的ID
     * @return 删除条数
     */
    public int deleteJobSchedule(Long id) {
        return jobScheduleDao.updateJobSchedule(new JobSchedule()
                .setId(id).setDeleted(true)
                .setOperatorId(UserInfoUtil.getUserId()).setOperatorName(UserInfoUtil.getUsername()));
    }

    /**
     * 切换开关
     *
     * @param id     主键
     * @param enable 是否开启
     * @return 切换条数
     */
    public int toggleEnable(Long id, Boolean enable) {
        return jobScheduleDao.updateJobSchedule(new JobSchedule()
                .setId(id).setScheduleEnable(enable)
                .setOperatorId(UserInfoUtil.getUserId()).setOperatorName(UserInfoUtil.getUsername()));
    }

    /**
     * 更新
     *
     * @param jobSchedule 执行信息对象
     * @return 更新条数
     */
    public int updateJobSchedule(JobSchedule jobSchedule) {
        jobSchedule.setOperatorId(UserInfoUtil.getUserId()).setOperatorName(UserInfoUtil.getUsername());
        return jobScheduleDao.updateJobSchedule(jobSchedule);
    }

    /**
     * 根据元数据ID查询
     *
     * @param jobMetaDataId 元数据ID
     * @return 查询结果
     */
    public List<JobSchedule> selectJobScheduleByJobMetaDataId(Long jobMetaDataId) {
        return jobScheduleDao.selectJobScheduleByJobMetaDataId(jobMetaDataId);
    }

    /**
     * 根据元数据ID查询数量
     *
     * @param jobMetaDataId 元数据ID
     * @return 查询结果
     */
    public Integer countJobScheduleByJobMetaDataId(Long jobMetaDataId) {
        return jobScheduleDao.countJobScheduleByJobMetaDataId(jobMetaDataId);
    }

    /**
     * 根据ID查询
     *
     * @param jobScheduleId 任务调度ID
     * @return 任务调度对象
     */
    public JobSchedule selectById(Long jobScheduleId) {
        return jobScheduleDao.selectById(jobScheduleId);
    }

    /**
     * 根据ID计数
     *
     * @param idList id集合
     * @return 数量
     */
    public Integer countByIdList(List<Long> idList) {
        return jobScheduleDao.countByIdList(idList);
    }

    /**
     * 查询待重新计算的执行信息
     *
     * @param startTime 起始时间
     * @param endTime 结束时间
     * @return 待重新计算的执行信息
     */
    public List<JobCalculateBO> selectJobForCalculate(LocalDateTime startTime, LocalDateTime endTime) {
        return jobScheduleDao.selectJobForCalculate(startTime, endTime);
    }

    /**
     * 计算正常下次执行时间
     *
     * @param jobCalculateBO 任务调度信息
     * @return 正常下次执行时间
     */
    public LocalDateTime calculateScheduleTime(JobCalculateBO jobCalculateBO) {
        JobCycleEnum jobCycle = JobCycleEnum.getByCode(jobCalculateBO.getJobCycle());
        LocalDateTime now = DateUtil.getNowLocalDateTime();
        LocalDateTime nextScheduleTime = switch (jobCycle) {
            case YEAR -> now.withMonth(jobCalculateBO.getCronMonth())
                    .withDayOfMonth(jobCalculateBO.getCronDay())
                    .withHour(jobCalculateBO.getCronHour())
                    .withMinute(jobCalculateBO.getCronMinute())
                    .withSecond(jobCalculateBO.getCronSecond());
            case MONTH -> now.withDayOfMonth(jobCalculateBO.getCronDay())
                    .withHour(jobCalculateBO.getCronHour())
                    .withMinute(jobCalculateBO.getCronMinute())
                    .withSecond(jobCalculateBO.getCronSecond());
            case WEEK -> now.with(ChronoField.DAY_OF_WEEK, DayOfWeek.of(jobCalculateBO.getCronDay()).getValue())
                    .withHour(jobCalculateBO.getCronHour())
                    .withMinute(jobCalculateBO.getCronMinute())
                    .withSecond(jobCalculateBO.getCronSecond());
            case DAY -> now.withHour(jobCalculateBO.getCronHour())
                    .withMinute(jobCalculateBO.getCronMinute())
                    .withSecond(jobCalculateBO.getCronSecond());
            case HOUR -> now.withMinute(jobCalculateBO.getCronMinute())
                    .withSecond(jobCalculateBO.getCronSecond());
            case MINUTE -> now.withSecond(jobCalculateBO.getCronSecond());
            default -> now;
        };
        if (nextScheduleTime.isBefore(now)) {
            return nextScheduleTime.plusMinutes(jobCycle.getMinutes());
        }
        return nextScheduleTime;
    }

    /**
     * 查询所有任务信息
     *
     * @param jobCycle          执行周期
     * @param currentScheduleId 当前调度信息ID
     * @return 所有任务信息
     */
    public List<JobScheduleNameVO> selectAllSchedule(Integer jobCycle, Long currentScheduleId) {
        return jobScheduleDao.selectAllSchedule(jobCycle, currentScheduleId);
    }

    /**
     * 根据调度配置ID查询调度周期
     *
     * @param jobScheduleId 调度配置ID
     * @return 调度周期
     */
    public Integer selectJobCycleByJobScheduleId(Long jobScheduleId) {
        return jobScheduleDao.selectJobCycleByJobScheduleId(jobScheduleId);
    }
}
